package cn.zwx.mvcframework.aop;

import cn.zwx.mvcframework.aop.advice.ZwxAdvice;
import cn.zwx.mvcframework.aop.support.ZwxAdvisedSupport;
import lombok.NoArgsConstructor;
import lombok.ToString;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;

/**
 * @author zhangwenxue
 */
@ToString
public class ZwxJdkDynamicAopProxy implements InvocationHandler {

    private ZwxAdvisedSupport advisedSupport;


    public ZwxJdkDynamicAopProxy(ZwxAdvisedSupport advisedSupport) {
        this.advisedSupport = advisedSupport;
    }


    public Object getProxy() {
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),this.advisedSupport.getTargetClass().getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 判断方法是否有对应的执行器链
        Map<String, ZwxAdvice> advices = advisedSupport.getAdvices(method);

        Object returnValue;
        try {
            this.invokeAdvice(advices.get("before"));
            returnValue = method.invoke(this.advisedSupport.getTarget(),args);
            this.invokeAdvice(advices.get("after"));
        }catch (Exception e){
            this.invokeAdvice(advices.get("afterThrowing"));
            throw e;
        }
        return returnValue;
    }

    /**
     * 执行切入点方法
     * @param advice 切入点
     */
    private void invokeAdvice(ZwxAdvice advice) {
        try {
            advice.getAdviceMethod().invoke(advice.getAspect());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
